#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <cassert>

using namespace std;

// 定义一个函数指针
typedef void (*functor)();

vector<functor> functors; //方法的集合

// for debug
unordered_map<uint32_t, string> info;

void f1() { cout << "这是一个处理日志的任务,执行的进程id: [" << getpid() << "]"
                 << "执行的时间是：[" << time(nullptr) << "]\n\n" << endl; }

void f2() { cout << "这是一个处理数据备份的任务,执行的进程id: [" << getpid() << "]"
                 << "执行的时间是：[" << time(nullptr) << "]\n\n" << endl; }

void f3() { cout << "这是一个处理网络连接的任务,执行的进程id: [" << getpid() << "]"
                 << "执行的时间是：[" << time(nullptr) << "]\n\n" << endl; }

void loadFunctor()
{
    info.insert({functors.size(), "处理日志任务"});
    functors.push_back(f1);

    info.insert({functors.size(), "数据备份任务"});
    functors.push_back(f2);

    info.insert({functors.size(), "处理网络连接任务"});
    functors.push_back(f3);
}

//第一个int32_t:进程pid
//第二个int32_t:该进程对应的管道写端fd
typedef pair<int32_t, int32_t> elem;
int processNum = 5;

void work(int blockFd)
{
    cout << "进程 [" << getpid() << "] 开始工作" << endl;
    //进行
    while (true)
    {
        //阻塞等待 获取任务信息
        uint32_t operatorCode = 0;
        ssize_t s = read(blockFd, &operatorCode, sizeof(uint32_t));
        if (s == 0)
            break;
        assert(s == sizeof(uint32_t));
        (void)s;

        //处理任务
        if (operatorCode < functors.size())
        {
            functors[operatorCode]();
        }
    }
    cout << "进程 [" << getpid() << "] 结束工作" << endl;
}
// [子进程的pid,子进程的管道fd]
void sendTask(const vector<elem> & processFds)
{
    srand((long long)time(nullptr));
    while (true)
    {
        sleep(1);

        //选择一个进程 选择进程是随机的 没有压着一个进程给任务
        //较为均匀的将任务给所有的子进程 --- 负载均衡
        uint32_t pick = rand() % processFds.size();

        // 选择任务
        uint32_t task = rand() % functors.size();

        //把任务给一个指定的进程
        write(processFds[pick].second, &task, sizeof(task));

        //打印对应的提示信息
        cout << "父进程指派任务 --> " << info[task] << "给进程：" << processFds[pick].first
             << "编号:" << pick << endl;
    }
}

int main()
{
    loadFunctor();
    vector<elem> assignMap;
    for (int i = 0; i < processNum; ++i)
    {
        //定义保存管道fd的对象
        int pipefd[2] = {0};
        //创建管道
        pipe(pipefd);
        pid_t id = fork();
        if (id == 0)
        {
            //子进程读取
            close(pipefd[1]);
            //子进程执行
            work(pipefd[0]);
            close(pipefd[0]);
            exit(0);
        }

        //父进程做得事情
        close(pipefd[0]);
        elem e(id, pipefd[1]);
        assignMap.push_back(e);
    }

    cout << "create all process success !" << endl;
    //父进程，派发任务
    sendTask(assignMap);

    // 回收资源
    for (int i = 0; i < processNum; ++i)
    {
        if (waitpid(assignMap[i].first, nullptr, 0) > 0)
            cout << "wait for : pid =  " << assignMap[i].first << " wait success"
                 << "number " << i << endl;
        close(assignMap[i].second);
    }
    return 0;
}

// 2. 父进程控制子进程
// int main()
// {
//     // 0. 加在任务列表
//     loadFunctor();
//     // 1.创建管道
//     int pipefd[2] = {0};
//     if (pipe(pipefd) != 0)
//     {
//         cerr << "pipe error" << endl;
//         return 1;
//     }

//     // 2.创建子进程
//     pid_t id = fork();
//     if (id < 0)
//     {
//         cerr << " fork error" << endl;
//         return 2;
//     }
//     else if (id == 0)
//     {
//         // child read
//         // 关闭不需要的fd
//         close(pipefd[1]);

//         while (true)
//         {
//             uint32_t operatorType = 0;

//             //如果有数据就读取 如果没有数据就阻塞等待
//             ssize_t s = read(pipefd[0], &operatorType, sizeof(uint32_t));
//             if(s == 0)
//             {
//                 cout << "我是子进程,我要退出了" <<endl;
//                 break;
//             }
//             assert(s == sizeof(uint32_t));
//             // assert断言 是编译有效的 debug模式
//             //但是如果是release模式下 断言就没有了
//             //一旦断言没有了，s变量就是只被定义没有被使用，一次你release模式下 可能有warning
//             (void)s;

//             if (operatorType < functors.size())
//             {
//                 functors[operatorType]();
//             }
//             else
//             {
//                 cerr << "bug? operatorTypr: " << operatorType << cout;
//             }
//         }

//         close(pipefd[0]);
//         exit(0);
//     }
//     else
//     {
//         srand((long long)time(nullptr));
//         close(pipefd[0]);
//         int num = functors.size();
//         int cnt = 10;
//         while (cnt--)
//         {
//             //形成任务码
//             uint32_t commandCode = rand() % num;
//             cout<< "父进程指派任务完成，任务是： " <<info[commandCode] <<
//             "任务的编号是：" << cnt << endl;
//             //想指定进程下答操作的任务
//             write(pipefd[1], &commandCode, sizeof(uint32_t));
//             sleep(1);
//         }
//         close(pipefd[1]);
//         pid_t res = waitpid(id, nullptr, 0);
//         if (res)
//             cout << " wait sucess  " << endl;
//     }

//     return 0;
// }

// //演示pipe管道通信的基本过程 -- 匿名管道
// int main()
// {
//     //1.创建管道
//     int pipefd[2] = {0};
//     if(pipe(pipefd) != 0)
//     {
//         cerr<<"pipe error"<<endl;
//         return 1;
//     }

//     //2.创建子进程
//     pid_t id = fork();
//     if(id<0)
//     {
//         cerr<<"fork error"<<endl;
//         return 2;
//     }
//     else if(id == 0)
//     {
//         //child  来进行读取
//         close(pipefd[1]);
//         char buffer[1024];
//         while(true)
//         {
//             cout<<"时间戳: "<< (uint32_t)time(nullptr)<<endl;
//             memset(buffer,0,sizeof(buffer));
//             ssize_t s = read(pipefd[0],buffer,sizeof(buffer) - 1 );
//             if(s>0)
//             {
//                 //读取成功
//                 buffer[s] = '\0';
//                 cout<<"子进程收到消息，消息的内容是："<< buffer <<endl;
//             }
//             else if(s == 0)
//             {
//                 cout<<"父进程写完了,我也退出了"<<endl;
//                 break;
//             }
//             else
//             {
//                 //do nothing
//             }
//         }

//         close(pipefd[0]);
//         exit(0);
//     }
//     else
//     {
//         //parent  来进行写入
//         close(pipefd[0]);
//         string msg = "你好子进程,我是父进程!";
//         int cnt = 0;
//         while(cnt<5)
//         {
//             write(pipefd[1],msg.c_str(),msg.size());
//             sleep(2);
//             cnt++;
//         }
//         close(pipefd[1]);
//         cout<<"父进程的工作结束了 退出"<<endl;
//     }
//     pid_t res =  waitpid(id,nullptr,0);
//     if(res > 0 )
//     {
//         cout<<"父进程等待成功"<<endl;
//     }
//     //pipefd[0]  是读
//     //pipefd[1]  是写

//     // cout<<"fd[0]:"<<pipefd[0]<<endl;
//     // cout<<"fd[1]:"<<pipefd[1]<<endl;
//     return 0;
// }